/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.easyplatform.studio.utils.apkrepackage;

import cn.easyplatform.studio.StudioApp;
import cn.easyplatform.studio.utils.apkrepackage.util.ApkSignedUtil;
import cn.easyplatform.studio.utils.apkrepackage.util.StringUtil;
import org.apache.commons.io.FileUtils;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;


/**
 * @author 潘凌
 */
public class APKSignatureService {

    private static APKSignatureService apkSignatureService;
    private final static Logger log = LoggerFactory.getLogger(APKSignatureService.class);
    public interface OnStatusListener{
        void onfinish();
    }

    public APKSignatureService() {
    }

    public static synchronized APKSignatureService getInstance() {
        if (apkSignatureService == null) {
            apkSignatureService = new APKSignatureService();
        }
        return apkSignatureService;
    }

    public String signature(APKInfo apkInfo,OnStatusListener onStatusListener) {
        synchronized (this){
            //当前的工作目录
            String path = StudioApp.getServletContext().getRealPath("/WEB-INF/mobileProduct");
            //apk的签名目录
            String apktoolPath = path + File.separator+"apkSigned"+File.separator+"apktool.jar";

            //校验apkInfo合法性
            //verifyApkInfo(apkInfo);

            /**
             * 编译和签名的根目录
             */
            String toolDirPath = apktoolPath.substring(0, apktoolPath.lastIndexOf(File.separator) + 1);
            //签名工具的目录
            String signapkPath = toolDirPath + "signapk.jar";
            String pemPath = toolDirPath + "cert.x509.pem";
            String pk8Path = toolDirPath + "private.pk8";

            //apk包的名称
            String apkPath = apkInfo.getApkPath();
            String apkName = apkPath.substring(apkPath.lastIndexOf(File.separator) + 1, apkPath.lastIndexOf(".apk"));
            Runtime run = Runtime.getRuntime();
            try {
                log.info("正在解包...");
                //解包命令
                String openJarCode = "java -jar " + apktoolPath + " d -f -s " + apkPath;
                Process p = run.exec(openJarCode, null, new File(toolDirPath));
                p.waitFor();

                //支持Android 7
                String forceCode = "java -jar " + apktoolPath + " empty-framework-dir --force";
                p = run.exec(forceCode, null, new File(toolDirPath));
                p.waitFor();
                log.info("解包成功。");

                log.info("正在修改AndroidManifest...");
                ApkSignedUtil.updateAndroidMainifest(toolDirPath + apkName + File.separator+"AndroidManifest.xml", apkInfo.getAppPackage(), apkInfo.getVersionCode(), apkInfo.getVersionName());
                log.info("修改AndroidManifest成功。");

                log.info("正在修改应用名称...");
                ApkSignedUtil.updateAppName(toolDirPath + apkName + File.separator+"res"+File.separator+"values"+File.separator+"strings.xml", apkInfo.getAppName());
                log.info("修改应用名称成功");

                log.info("正在修改url...");
                ApkSignedUtil.updateUrl(toolDirPath + apkName + File.separator+"res"+File.separator+"values"+File.separator+"strings.xml",apkInfo.getUrl());
                log.info("修改url成功");

                log.info("正在修改应用图标启动图...");
                String iconDirPath = toolDirPath + apkName + File.separator+"res"+File.separator+"drawable-mdpi"+File.separator;
                File iconDir = new File(iconDirPath);
                if (iconDir.exists()) {
                    Files.copy(Paths.get(apkInfo.getmIcon()), Paths.get(toolDirPath + apkName +File.separator+ "res"+File.separator+"drawable-mdpi"+File.separator+"icon.png"), StandardCopyOption.REPLACE_EXISTING);
                    Files.copy(Paths.get(apkInfo.getmSplash()), Paths.get(toolDirPath + apkName + File.separator+"res"+File.separator+"drawable-mdpi"+File.separator+"splash.png"), StandardCopyOption.REPLACE_EXISTING);
                } else {
                    Files.copy(Paths.get(apkInfo.getmIcon()), Paths.get(toolDirPath + apkName + File.separator+"res"+File.separator+"drawable-mdpi"+File.separator+"icon.png"), StandardCopyOption.REPLACE_EXISTING);
                    Files.copy(Paths.get(apkInfo.getmSplash()), Paths.get(toolDirPath + apkName + File.separator+"res"+File.separator+"drawable-mdpi"+File.separator+"splash.png"), StandardCopyOption.REPLACE_EXISTING);
                }
                log.info("修改应用图标启动图");

                if (StringUtil.isNotEmpty(apkInfo.getResPath())) {
                    log.info("正在设置应用配置...");
                    File sourceFile = new File(apkInfo.getResPath());
                    File targetFile = new File(toolDirPath + apkName + File.separator+"res"+File.separator+"raw"+File.separator+"res_decrypted.zip");
                    if (!sourceFile.exists()) {
                        log.info("应用配置不存在，请检查路径！");
                        throw new IllegalArgumentException("应用配置不存在，请检查路径！");
                    }

                    FileUtils.copyFile(sourceFile, targetFile);
                    log.info("设置应用配置成功");
                }

                log.info("正在重新打包...");

                String packJarCode = "java -jar " + apktoolPath + " b " + apkName;
                p = run.exec(packJarCode, null, new File(toolDirPath));
                p.waitFor();

                log.info("重新打包成功。");

                log.info("正在签名...");

                //String sinedApkName = toolDirPath + apkInfo.getAppName() + "-" + apkInfo.getVersionName() + ".apk";
                String sinedApkName = toolDirPath + "epApp.apk";
                String signedApkCode = "java -jar " + signapkPath + " " + pemPath + " " + pk8Path + " " + toolDirPath + apkName + File.separator+"dist"+File.separator + apkName + ".apk" + " " + sinedApkName;
                p = run.exec(signedApkCode, null, new File(toolDirPath));
                p.waitFor();
                log.info("签名成功。");
                log.info("生成apk：" + sinedApkName);

                FileUtils.deleteDirectory(new File(toolDirPath + apkName));
                if (onStatusListener != null)
                    onStatusListener.onfinish();
                return sinedApkName;
            } catch (IOException | DocumentException | InterruptedException e) {
                log.info(e.getMessage());
                try {
                    FileUtils.deleteDirectory(new File(toolDirPath + apkName));
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                return null;
            }
        }
    }

    private void verifyApkInfo(APKInfo apkInfo) {
        if (StringUtil.isEmpty(apkInfo.getApkPath())) {
            log.info("APK Path不能为空。");
        }
        if (!new File(apkInfo.getApkPath()).exists()) {
            log.info("APK文件不存在。");
        }

        if (StringUtil.isEmpty(apkInfo.getVersionCode())) {
            log.info("版本号不能为空。");
        }

        if (StringUtil.isEmpty(apkInfo.getVersionName())) {
            log.info("版本名称不能为空。");
        }

        if (StringUtil.isEmpty(apkInfo.getAppPackage())) {
            log.info("应用包名不能为空。");
        }

        if (StringUtil.isEmpty(apkInfo.getAppName())) {
            log.info("应用名称不能为空。");
        }

        if (StringUtil.isEmpty(apkInfo.getmIcon())) {
            log.info("mIcon不能为空。");
        }
        if (!new File(apkInfo.getmIcon()).exists()) {
            log.info("mIcon不存在。");
        }

        if (StringUtil.isEmpty(apkInfo.gethIcon())) {
            log.info("hIcon不能为空。");
        }
        if (!new File(apkInfo.gethIcon()).exists()) {
            log.info("hIcon不存在。");
        }

        if (StringUtil.isEmpty(apkInfo.getXxhIcon())) {
            log.info("xxhIcon不能为空。");
        }
        if (!new File(apkInfo.getXxhIcon()).exists()) {
            log.info("xxhIcon不存在。");
        }

        if (StringUtil.isEmpty(apkInfo.getXxxhIcon())) {
            log.info("xxxhIcon不能为空。");
        }
        if (!new File(apkInfo.getXxxhIcon()).exists()) {
            log.info("xxxhIcon不存在。");
        }
    }

}
